package com.yangchuang.openpicture.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionContentPart;
import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionContentPart.ChatCompletionContentPartImageURL;
import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionRequest;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessage;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole;
import com.volcengine.ark.runtime.service.ArkService;
import com.yangchuang.openpicture.communication.ResultCode;
import com.yangchuang.openpicture.constant.FileSizeConstants;
import com.yangchuang.openpicture.constant.PictureOwnerRedisConstants;
import com.yangchuang.openpicture.constant.PictureVisibilityConstants;
import com.yangchuang.openpicture.constant.ThreadLocalConstants;
import com.yangchuang.openpicture.exception.BussinessException;
import com.yangchuang.openpicture.mapper.PictureMapper;
import com.yangchuang.openpicture.pojo.Picture;
import com.yangchuang.openpicture.property.DoubaoAiProperties;
import com.yangchuang.openpicture.property.LocalStorageProperties;
import com.yangchuang.openpicture.service.PictureService;
import com.yangchuang.openpicture.util.BaseContext;
import com.yangchuang.openpicture.util.RedisUtils;
import com.yangchuang.openpicture.vo.AiPictureInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@Service
@Slf4j
@RequiredArgsConstructor
public class PictureServiceImpl extends ServiceImpl<PictureMapper, Picture> implements PictureService {

    private final PictureMapper pictureMapper;
    private final ArkService service; // 由 Spring 注入，需配置类初始化（见下方）
    private final RedisUtils redisUtils;
    private final PictureService pictureService;

    private final DoubaoAiProperties doubaoAiProperties;
    private final LocalStorageProperties localStorageProperties;

    private final ObjectMapper objectMapper = new ObjectMapper();

    // Base64 编码方法（保持原样，20MB 限制下安全）
    private String encodeImage(String imagePath) throws IOException {
        byte[] imageBytes = Files.readAllBytes(Path.of(imagePath));
        return Base64.getEncoder().encodeToString(imageBytes);
    }


    @Override
    public String PictureOwnerUpdate(Long pictureId) {
        //1.先去redis里面查 这里的key能够区分到某张具体的图片即可
        String key = PictureOwnerRedisConstants.PICTURE_OWNER_STRING + pictureId;
        String userId = (String) redisUtils.stringOps().getValue(key);
        if (userId == null) {
            Long pictureOwnerId = pictureService.getPictureOwnerIDByPictureID(pictureId);
            if (pictureOwnerId != null) {
                //存入redis里面
                redisUtils.stringOps().setValueAndExpire(key, String.valueOf(pictureOwnerId), PictureOwnerRedisConstants.PICTURE_OWNER_TTL_SECONDS, TimeUnit.SECONDS);
            }
            return String.valueOf(pictureOwnerId);
        }
        return redisUtils.stringOps().getValue(key);

    }

    @Override
    public Long insertPicture(long fileSize,
                              String publicUrl,
                              Long categoryId,
                              String pictureName,
                              String description,
                              List<String> tags,
                              int width,
                              int height) {
        String userId = (String) BaseContext.get(ThreadLocalConstants.USER_ID);
        log.info("用户{}上传图片", userId);
        Picture picture = new Picture();
        picture.setUserId(Long.parseLong(userId));
        picture.setCategoryId(categoryId);
        picture.setName(pictureName);
        picture.setUrl(publicUrl);
        picture.setDescription(description);
        picture.setSize(fileSize);
        picture.setWidth(width);
        picture.setHeight(height);
        picture.setTags(tags);
        picture.setVisibility(PictureVisibilityConstants.PUBLIC);
        pictureMapper.insert(picture);
        return picture.getId();
    }

    @Override
    public AiPictureInfo aiPicture(MultipartFile file) throws IOException {
        // 1. 基础参数校验
        if (file.isEmpty()) {
            throw new BussinessException(ResultCode.EMPTY_PICTURE);
        }

        // 2. 文件大小校验
        long size = file.getSize();
        if (size > FileSizeConstants.SINGLE_FILE_MAX_SIZE) {
            throw new BussinessException(ResultCode.FILE_SIZE_EXCEEDED);
        }

        // 3. 保存图片到本地
        Path localDir = Paths.get(localStorageProperties.getPicturePath());
        if (!Files.exists(localDir)) {
            Files.createDirectories(localDir);
        }

        String originalFilename = file.getOriginalFilename();
        if (!StringUtils.hasText(originalFilename) || !originalFilename.contains(".")) {
            throw new BussinessException(ResultCode.INVALID_FILE_FORMAT);
        }

        // 安全清理文件名（防路径穿越）
        originalFilename = StringUtils.cleanPath(originalFilename);

        String fileSuffix = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();        // 标准化扩展名（统一转为 .jpeg）
        String normalizedSuffix = fileSuffix.equalsIgnoreCase(".jpg") ? ".jpeg" : fileSuffix.toLowerCase();
        System.out.println("====================");
        System.out.println("标准后缀名：" + normalizedSuffix);
        // 生成文件名
        String localFileName = UUID.randomUUID().toString() + normalizedSuffix;
        Path filePath = localDir.resolve(localFileName);

        try {
            try {
                Files.write(filePath, file.getBytes());
            } catch (IOException e) {
                log.error("写入临时文件失败: {}", filePath, e);
                throw new BussinessException(ResultCode.INTERNAL_ERROR);
            }

            System.out.println("临时文件已经保存到电脑本地");
            // 4. 调用 AI 接口
            String rightSuffix = normalizedSuffix.substring(1);
            System.out.println(rightSuffix);//正确
            System.out.println(filePath);
            String base64Data = "data:image/" + rightSuffix + ";base64," + encodeImage(String.valueOf(filePath));

            List<ChatCompletionContentPart> contentParts = new ArrayList<>();
            contentParts.add(ChatCompletionContentPart.builder()
                    .type("image_url")
                    .imageUrl(new ChatCompletionContentPartImageURL(base64Data))
                    .build());

            // 文本提示 —— 要求返回 JSON
            String prompt = """
                    请严格按照以下 JSON 格式返回分析结果，不要包含任何其他文字或说明：
                    {
                      "name": "简洁名称（10字以内）",
                      "description": "详细描述（50-100字）",
                      "tags": ["标签1", "标签2", "标签3"]
                    }
                    """;

            contentParts.add(ChatCompletionContentPart.builder()
                    .type("text")
                    .text(prompt)
                    .build());

            List<ChatMessage> messages = List.of(ChatMessage.builder()
                    .role(ChatMessageRole.USER)
                    .multiContent(contentParts)
                    .build());

            ChatCompletionRequest req = ChatCompletionRequest.builder()
                    .model(doubaoAiProperties.getModel())
                    .messages(messages)
                    .thinking(new ChatCompletionRequest.ChatCompletionRequestThinking("disabled"))
                    .build();

            String aiResponse;
            try {
                var response = service.createChatCompletion(req);
                if (response.getChoices() == null || response.getChoices().isEmpty()) {
                    throw new BussinessException(ResultCode.AI_RESPONSE_EMPTY);
                }
                aiResponse = (String) response.getChoices().get(0).getMessage().getContent();
                log.debug("AI 响应内容: {}", aiResponse);
            } catch (Exception e) {
                log.error("调用 AI 服务失败", e);
                throw new BussinessException(ResultCode.AI_PROCESS_FAILED);
            }

            // 5. 解析 AI 响应（JSON 格式）
            return parseAiResponseJson(aiResponse);

        } finally {
            // 6. 清理临时文件
            try {
                if (Files.exists(filePath)) {
                    Files.delete(filePath);
                    log.debug("临时文件已删除: {}", filePath);
                }
            } catch (IOException e) {
                log.warn("清理临时文件失败: {}", filePath, e);
            }
        }
    }


    @Override
    public AiPictureInfo parseAiResponseJson(String json) {
        try {
            AiPictureInfo info = objectMapper.readValue(json, AiPictureInfo.class);
            // 校验并设置默认值
            if (!StringUtils.hasText(info.getName())) {
                info.setName("AI识别失败");
            }
            if (!StringUtils.hasText(info.getDescription())) {
                info.setDescription("AI识别失败，请稍后再试");
            }
            if (info.getTags() == null || info.getTags().isEmpty()) {
                info.setTags(List.of("AI识别失败"));
            }
            return info;
        } catch (Exception e) {
            log.error("解析 AI JSON 响应失败: {}", json, e);
            AiPictureInfo fallback = new AiPictureInfo();
            fallback.setName("AI识别失败");
            fallback.setDescription("AI识别失败，请稍后再试");
            fallback.setTags(List.of("失败"));
            return fallback;
        }
    }

    @Override
    public void batchdelete(List<String> publicUrls) {
        //批量删除
        pictureMapper.batchDeleteByUrls(publicUrls);
    }

    @Override
    public void batchhide(List<String> publicUrls) {
        //批量删除
        pictureMapper.batchHideByUrls(publicUrls);
    }

    @Override
    public void batchopen(List<String> publicUrlS) {
        pictureMapper.batchOpenByUrls(publicUrlS);
    }

    @Override
    public Long getPictureOwnerIDByPictureID(Long pictureID) {
        return pictureMapper.getPictureOwnerIDByPictureID(pictureID);
    }


}